/*
 * Copyright (c) 2025 Huawei Device, Inc. Ltd. and <马弓手>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "CompassListener.h"
#include "CordovaViewController.h"
#include "cJSON.h"
REGISTER_PLUGIN_CLASS(CompassListener)
bool CompassListener::execute(const string&  action, cJSON* args, CallbackContext cbc)
{
    if(action == "start") {
        CreateSubscribeInfo();
    }
    
    if(action == "stop" || action == "stopHeading") {
        if(m_isStatus) {
            DestroySubscribeInfo();
        }
    }
    if(action == "getStatus") {
        PluginResult pluginResult(PluginResult::OK, m_isStatus);
        cbc.sendPluginResult(pluginResult);
    }
    if(action == "getHeading") {
        //js接口会一直调用此函数，其实没有必要，使用此插件，建议修改js侧接口，因为变化后会进行通知的，这个是原接口设计者的缺陷
        m_cbc = cbc;
        if(!m_isStatus) {
            cJSON* pObj = cJSON_GetArrayItem(args, 0);
            if(pObj != nullptr) {
                cJSON* pFrequency = cJSON_GetObjectItem(pObj, "frequency");
                if(pFrequency != nullptr && pFrequency->type == cJSON_Number) {
                    m_nFrequency = pFrequency->valueint;
                }
                cJSON* pTimeout = cJSON_GetObjectItem(pObj, "timeout");
                if(pTimeout != nullptr && pTimeout->type == cJSON_Number) {
                    m_nTimeOut = pTimeout->valueint;
                }
            }
            if(!CreateSubscribeInfo()) {
                PluginResult pluginResult(PluginResult::ERROR, 3);
                cbc.sendPluginResult(pluginResult);
            } 
        } else {
            cJSON* pJson = cJSON_CreateObject();
            cJSON_AddNumberToObject(pJson, "timestamp", m_timestamp);
            cJSON_AddNumberToObject(pJson, "magneticHeading", m_magneticHeading);
            cJSON_AddNumberToObject(pJson, "trueHeading", m_trueHeading);
            cJSON_AddNumberToObject(pJson, "headingAccuracy", m_headingAccuracy);
            PluginResult pluginResult(PluginResult::OK, pJson);
            pluginResult.setKeepCallback(true);
            m_cbc.sendPluginResult(pluginResult);
            cJSON_Delete(pJson);
        }
    }
    if(action == "setTimeout") {
       cJSON* pJson = cJSON_GetArrayItem(args, 0);
        if(pJson != nullptr && pJson->type == cJSON_Number) {
            m_nTimeOut = pJson->valueint;
        }
    }
    if(action == "getTimeout") {
        PluginResult pluginResult(PluginResult::OK, m_nTimeOut);
        cbc.sendPluginResult(pluginResult);
    }
    return true;
}

bool CompassListener::CreateSubscribeInfo()
{
    m_user = OH_Sensor_CreateSubscriber();                                         // 创建一个Sensor_Subscriber实例。
    int32_t ret = OH_SensorSubscriber_SetCallback(m_user, CompassListener::onRevice); // 设置一个回调函数来报告传感器数据。
    if (ret != SENSOR_SUCCESS) {
        return false;
    }

    Sensor_Type SENSOR_ID  = SENSOR_TYPE_GYROSCOPE;
    m_id = OH_Sensor_CreateSubscriptionId(); // 创建一个Sensor_SubscriptionId实例。
    ret = OH_SensorSubscriptionId_SetType(m_id, SENSOR_ID);         // 设置传感器类型。
    if (ret != SENSOR_SUCCESS) {
        return false;
    }

    int64_t SENSOR_SAMPLE_PERIOD = m_nFrequency*1000*1000;//ns
    m_attr = OH_Sensor_CreateSubscriptionAttribute();     // 创建Sensor_SubscriptionAttribute实例。
    ret = OH_SensorSubscriptionAttribute_SetSamplingInterval(m_attr, SENSOR_SAMPLE_PERIOD); // 设置传感器数据报告间隔。
    if (ret != SENSOR_SUCCESS) {
        return false;
    }

    ret = OH_Sensor_Subscribe(m_id, m_attr, m_user); // 订阅传感器数据。
    if (ret != SENSOR_SUCCESS) {
        return false;
    }
    
    m_lngLastAccessTime = time(NULL);
    m_isStatus = true;
    return true;
}

void CompassListener::DestroySubscribeInfo()
{
    int32_t ret = OH_Sensor_Unsubscribe(m_id, m_user); // 取消订阅传感器数据。
    if (ret != SENSOR_SUCCESS) {
        return;
    }
    if (m_id != nullptr) {
        OH_Sensor_DestroySubscriptionId(m_id); // 销毁Sensor_SubscriptionId实例并回收内存。
        m_id = nullptr;
    }
    if (m_attr != nullptr) {
        OH_Sensor_DestroySubscriptionAttribute(m_attr); // 销毁Sensor_SubscriptionAttribute实例并回收内存。
        m_attr = nullptr;
    }
    if (m_user != nullptr) {
        OH_Sensor_DestroySubscriber(m_user); // 销毁Sensor_Subscriber实例并回收内存。
        m_user = nullptr;
    }
    m_isStatus = false;
    return;
}

void CompassListener::onRevice(Sensor_Event *event)
{
    CompassListener* pAccelListener = (CompassListener*)((CordovaViewController*)Application::g_cordovaViewController)->getPluginManager()->getPlugin("Compass");
    pAccelListener->updateAccelInfo(event);
}

void CompassListener::updateAccelInfo(Sensor_Event *event)
{
    if (event == nullptr) {
        return;
    }
    int32_t ret = OH_SensorEvent_GetTimestamp(event, &m_timestamp); // 获取传感器数据的时间戳。
    if (ret != SENSOR_SUCCESS) {
        return;
    }
    Sensor_Type sensorType;
    ret = OH_SensorEvent_GetType(event, &sensorType); // 获取传感器类型。
    if (ret != SENSOR_SUCCESS) {
        return;
    }
    Sensor_Accuracy accuracy = SENSOR_ACCURACY_UNRELIABLE;
    ret = OH_SensorEvent_GetAccuracy(event, &accuracy); // 获取传感器数据的精度。
    if (ret != SENSOR_SUCCESS) {
        return;
    }
    float *data = nullptr;
    uint32_t length = 0;
    ret = OH_SensorEvent_GetData(event, &data, &length); // 获取传感器数据。
    if (ret != SENSOR_SUCCESS) {
        return;
    }
    if (data == nullptr) {
        return;
    }
    OH_LOG_Print(LOG_APP, LOG_INFO, 0xff00, "CompassListener","sensorType:%{public}d, dataLen:%{public}d, accuracy:%{public}d", sensorType, length, accuracy);
   
    for (uint32_t i = 0; i < length; ++i) {
        if(i == 0) {
            m_magneticHeading = data[i];
        } 
        if(i == 1) {
            m_trueHeading = data[i];
        }
        if(i == 2) {
            m_headingAccuracy = data[i];
        }
        
        OH_LOG_Print(LOG_APP, LOG_INFO, 0xff00, "CompassListener", "data[%{public}d]:%{public}f", i, data[i]);
    }
    
    cJSON* pJson = cJSON_CreateObject();
    cJSON_AddNumberToObject(pJson, "timestamp", m_timestamp);
    cJSON_AddNumberToObject(pJson, "magneticHeading", m_magneticHeading);
    cJSON_AddNumberToObject(pJson, "trueHeading", m_trueHeading);
    cJSON_AddNumberToObject(pJson, "headingAccuracy", m_headingAccuracy);
    PluginResult pluginResult(PluginResult::OK, pJson);
    pluginResult.setKeepCallback(true);
    m_cbc.sendPluginResult(pluginResult);
    cJSON_Delete(pJson);
    
    time_t timeStamp = time(NULL);
    if(timeStamp- m_lngLastAccessTime > m_nTimeOut) {
        DestroySubscribeInfo();
    }
}
